Skip to content

FIX Stop JSON retries for adversarial refusals - #2443

Open
hannahwestra25 wants to merge 4 commits into
microsoft:mainfrom
hannahwestra25:hannahwestra25-fix-refusal-retries
Open

FIX Stop JSON retries for adversarial refusals#2443
hannahwestra25 wants to merge 4 commits into
microsoft:mainfrom
hannahwestra25:hannahwestra25-fix-refusal-retries

Conversation

@hannahwestra25

@hannahwestra25 hannahwestra25 commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Description

OpenAI structured refusals arrive as blocked/error Messages, but the shared adversarial conversation manager parsed them as malformed JSON and exhausted the JSON retry budget.

This change detects errored messages before parsing and raises BadRequestException, so TAP, Red Teaming, and Crescendo all stop retrying deterministic failures. TAP prunes the affected node; Red Teaming and Crescendo fail through the standard strategy lifecycle. Malformed normal responses still retry.

Tests and Documentation

  • Added regression tests for one-call refusal handling and malformed-JSON retries.
  • Passed 78 manager, 11 focused TAP, and 150 Red Teaming/Crescendo tests.
  • Passed Ruff and ty for changed files.
  • No documentation changes; public APIs are unchanged.

Detect blocked and errored adversarial chat responses before schema parsing so terminal target failures do not consume the malformed-JSON retry budget.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@hannahwestra25
hannahwestra25 marked this pull request as ready for review August 20, 2026 21:59
@hannahwestra25 hannahwestra25 changed the title [DRAFT] FIX Stop JSON retries for adversarial refusals FIX Stop JSON retries for adversarial refusals Aug 20, 2026
@romanlutz

Copy link
Copy Markdown
Contributor

Red Teaming and Crescendo retain their existing error handling.

Aren't they all using the same adv conv manager?

@hannahwestra25

Copy link
Copy Markdown
Contributor Author

Red Teaming and Crescendo retain their existing error handling.

Aren't they all using the same adv conv manager?

yes updated the description!


def _parse(response: Message) -> AdversarialReply:
if response.is_error():
raise BadRequestException(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we preserve the error type or status here? response.is_error() also covers errors such as processing and unknown, so an upstream server failure could become BadRequestException(400) and look like a client-side refusal. For example, we could use BadRequestException only for blocked responses and propagate another terminal exception for other error responses. Let me know if I misunderstood the intended normalization. If you think this is fine that's also ok.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants